home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Collection of Tools & Utilities
/
Collection of Tools and Utilities.iso
/
tex
/
concat10.zip
/
CONCAT10.ASM
< prev
next >
Wrap
Assembly Source File
|
1989-05-02
|
12KB
|
506 lines
TITLE Concat
;Input:
; Read in multiple files (as named on the DOS cmd line).
; Wildcards and full pathing are supported.
;
;Output:
; To StdOut (e.g., via redirection at the DOS command line).
; (No ^Z is appended to the output.)
;
;End of File:
; Assumes the first ^Z in each file is EOF (and the rest is garbage),
; so will discard everything after that first ^Z.
;Notes:
; Makes no attempt to add terminating CR/LF to each file
; or any other such cleanup.
;Released to the public domain
;David Kirschbaum
;Toad Hall
;kirsch@braggvax.ARPA
CR equ 0DH
LF equ 0AH
CTRLZ equ 1AH ;Ctrl-Z
STDOUT equ 1 ;DOS StdOut
STDERR equ 2 ;DOS StdErr (screen)
DTA_TYPE struc
reserved db 21 DUP(?) ;Used by DOS for find next
attrib db ? ;file attribute
time dw ? ;file time stamp
date dw ? ;file date stamp
filesize dw ?,? ;file size in bytes (long integer)
filename db 13 DUP(?) ;AsciiZ filename string
DTA_TYPE ends
CSEG segment public 'CODE'
assume CS:CSEG,DS:CSEG
org 80H
dta label DTA_TYPE
nchar db ? ;for Args
params db ?
; org fcb_dta + 26 ;dta filesize
;filesize dw ?,?
;
; org dta + 30 ;DTA.filename
;dtaname db ? ;for wildcard expansion
org 100H ;yep, a .COM file
Concat proc near
jmp Start ;skip over data
usagemsg db 'CONCAT - Concatenate text files to StdOut',CR,LF
db 'Usage: CONCAT [d:\]file1.txt file2.txt >output.txt',CR,LF
db 'Input: Wildcards and full pathing permitted.',CR,LF
db 'Output: DOS Standard Output (redirectable).',CR,LF
db 'David Kirschbaum, Toad Hall, v1.0'
crlf db CR,LF
USAGEMSGLEN equ $ - usagemsg
CRLFLEN equ $ - crlf
notfoundmsg db ' not found',CR,LF
NOTFOUNDLEN equ $ - notfoundmsg ;msg length
openerrmsg db ' File open error',CR,LF
OPENERRLEN equ $ - openerrmsg
readerrmsg db ' File read error',CR,LF
READERRLEN equ $ - readerrmsg
writerrmsg db ' File write error',CR,LF
WRITERRLEN equ $ - writerrmsg
zerofilemsg db ' Empty file, skipped',CR,LF
ZEROFILELEN equ $ - zerofilemsg
handle dw 0 ;input file handle
Concat endp
;Returns position of char in string
;DI -> string start or end
;AL = char to seek
;Returns psn in CX
;It'll work in reverse also if you enter with DI -> string end
;and STD instead of CLD
Find_Char proc near
mov cx,0FFFFH ;max scan
repne scasb
not cx ;CX=char psn
ret
Find_Char endp
;Display an AsciiZ string to StdErr
;Enters with SI -> AsciiZ string
;Destroys AX,DI
;Returns CX = string length, DX, SI -> AsciiZ string
Pr_AsciiZ proc near
xor al,al ;find terminating 0
mov di,si ;from string start
cld ;go forward
call Find_Char ;CX = psn of 0, SI unchanged
dec cx ;- 1 for actual length
mov dx,si ;string start
mov bx,STDERR ;output to StdErr
mov ah,40H ;write to file/device
int 21H
ret
Pr_AsciiZ endp
;Separate a drive:\path from an arg filename.
;SI -> arg (an AsciiZ string)
;Pointer pathend -> beyond last char in path (filename[0] if none)
Split_Path proc near
mov di,si ;from string start
xor al,al ;find AsciiZ arg end
cld ;go forward
call Find_Char ;CX=psn of 0, DI -> beyond 0
dec di ;DI -> AsciiZ 0
dec di ;DI -> last char in filename
mov al,'\' ;scan for subdirectories
std ;backwards towards start
repne scasb ;CX has filename length
cld ;insure forward again
or cx,cx ;any path?
jnz Got_Path ;yep
;No '\',how about ':'?
xor cx,cx ;assume no path, no move
mov di,si ;string start
cmp byte ptr 1[di],':' ;divider should be after drive char
jnz No_Path ;nope, DI -> filename's first char
;In either case, DI should be pointing to the char
;BEFORE the path or drive separator.
Got_Path:
add di,2 ;bump beyond '\' or ':'
mov cx,di ;path\filename end
sub cx,si ;- path end = bytes to move
No_Path:
mov di,offset path ;move into path
jcxz No_Path_Move
rep movsb ;copy args path into buffer
No_Path_Move:
mov word ptr pathptr,di ;pathptr -> char beyond args path
;where we'll move the filename
Split_Path endp
;Move our expanded filename after our arg path.
Add_Path proc near
mov si,offset dta.filename ;expanded filename
mov di,si ;Find_Char wants it in DI
xor al,al ;get AsciiZ name length
cld ;forward
call Find_Char ;CX = char psn, SI unchanged
mov di,word ptr pathptr ;-> arg path + 1 (or start)
rep movsb ;move in the name
;(include the AsciiZ 0)
mov si,offset path ;-> path start
ret
Add_Path endp
;Displays expanded filename
;Copies the wildcard file to StdOut
;Enter with SI -> expanded filename
;On return:
; handle = file handle (or 0 if never opened)
; CF set = error
; DX=CR/LF or error msg (if error)
; CX = msg length
Copy_File proc near
mov handle,0 ;insure file handle is cleared
call Add_Path ;add arg path to expanded filename
;(we could be doing a Find Next)
;returns SI, DX -> path:\name
call Pr_AsciiZ ;display AsciiZ name
;DX -> AsciiZ path:\name
mov ax,3D00H ;open for read only
int 21H
jb Open_Err ;failed
mov handle,ax ;save the handle
mov si,offset dta.filesize ;DTA filesize long integer
lodsw ;get filesize.lo
or ax,[si] ;test filesize.hi
jz Zero_File ;empty file, forget it
ReadLup:
mov dx,offset readbuff ;file read buffer
mov cx,READBUFFSIZE ;bytes to read
mov bx,handle ;file handle
mov ah,3FH ;read from file/device
int 21H
jb Read_Err ;read failed
mov cx,ax ;bytes read
jcxz File_Eof1 ;nothing read, it's EOF
mov bx,ax ;remember bytes read
mov di,dx ;DI -> read buffer
mov al,CTRLZ ;scan for terminating Ctrl Z
repne scasb
jz File_EOF ;it's logical EOF
mov cx,bx ;restore nr bytes read
mov bx,STDOUT ;output to StdOut
mov ah,40H ;write to file/device
int 21H
jnb ReadLup ;wrote ok, keep going
Write_Err:
mov dx,offset writerrmsg ;' File write error'
mov cx,WRITERRLEN
ret ;CF set
Zero_File:
mov dx,offset zerofilemsg ;' Zero file size .. skipped'
mov cx,ZEROFILELEN
ret ;CF clear
Read_Err:
mov dx,offset readerrmsg ;' File read error'
mov cx,READERRLEN
ret ;CF set
File_Eof:
inc cx ;adjust for that Ctrl Z
sub bx,cx ; bytes read - Ctrl Z psn
mov cx,bx ;= bytes to write
mov bx,STDOUT ;output to StdOut
mov ah,40H ;write to file/device
int 21H
jb Write_Err ;final write failed
File_Eof1:
mov dx,offset crlf ;new line after filename
mov cx,CRLFLEN
ret ;CF should be clear
Open_Err:
mov dx,offset openerrmsg ;'File open error'
mov cx,OPENERRLEN
ret ;CF set
Copy_File endp
;Do a wildcard copy.
;SI -> AsciiZ filename
OutPut proc near
mov dx,si ;DX = AsciiZ filename ptr
xor cx,cx ;no special attributes
mov ah,4EH ;find first
int 21H
or ax,ax ;find anything?
jz Found_First ;yep
call Pr_AsciiZ ;display filename (still in SI)
mov dx,offset notfoundmsg ;' not found'
mov cx,NOTFOUNDLEN ;msg length
stc ;CF set to exit
jmp short Not_Found ;display error msg, return
;Remember, a Find First or Find Next will give us an expanded filename
;(in the DTA) but will NOT give us a path!
;We have to process the arg (SI still points to it) and split off
;the path from the filename.
Found_First:
call Split_Path ;separate arg path from arg
;arg filename (for Find First only).
;fall thru to...
Find_Next: ;our wildcard loop
call Copy_File ;open, copy the file
;On return:
; handle = file handle (or 0 if never opened)
; CF set = error
; DX=CR/LF or error msg (if error)
; CX = msg length
Not_Found:
pushf ;save copy flags
mov bx,STDERR ;Std Err handle
mov ah,40H ;write to file/device
int 21H
mov bx,handle ;restore input file handle
or bx,bx ;ever opened?
jz No_Handle ;nope
mov ah,3EH ;close input file
int 21H
No_Handle:
popf ;restore copy flags
jb OutPutX ;some sort of error
;Now for the Find Next
mov ah,4FH ;continue file search
int 21H
cmp al,18 ;no more files to be found?
jnz Find_Next ;nope, found one, continue
Out